home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-24 | 42.0 KB | 1,232 lines | [TEXT/pdos] |
- *******************************************************************************
- *
- * BoxCtl CDEFProc -- Version 3.0
- *
- * (C) Copyright Apple Computer, Inc. 1988-1990
- * All rights reserved.
- *
- * Developer Technical Support Apple II Sample Code
- *
- * by Keith Rollin
- *
- *******************************************************************************
- *
- myDragCtl start
- *
- * Description: Drag command. We hit something. Determine what it was and
- * drag it around the screen. If we hit the frame, then drag
- * the whole control. If we hit a knob, then we grow the
- * control (just like growing a window).
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs:
- * Import SetMyPen
- * Import Snap2Grid
- * Import myDrawCtl
- * Import FindPart
- * Import SetCtlRect
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- PushLong #oldPenState ; save drawing state, as we change it
- _GetPenState
-
- ldy #6 ; make a working copy of CtlRect.
- loop100 lda myCtlRect,y
- sta drag_rect,y
- dey
- dey
- bpl loop100
-
- pha ; has the mouse been lifted up?
- PushWord #mUpMask ; ask for any such events
- PushLong #TrackEvent
- _GetNextEvent
- pla
-
- lda TrackEvent+owhat
- cmp #mouseUpEvt ; was there a mouse up event?
- bne mDown ; no - so start tracking
- brl done ; yes - so leave
-
- mDown ANOP
- PushLong #TrackEvent+owhere
- _GlobalToLocal
-
- lda TrackEvent+owhere
- sta OldMouse ; FindPart likes the mouse Position
- sta theParam ; in 'theParam'
- lda TrackEvent+owhere+2
- sta OldMouse+2
- sta theParam+2
-
- jsr FindPart ; what did we hit? (returns internal
- sta dragPart ; partcode number).
-
- cmp #InteriorPart+1 ; what part did we hit?
- bge GrowFrame ; some knob - grow the control
- brl DragFrame ; interior or frame - move the control
-
- ;
- ; This part of the program is called when we detect that we have clicked on
- ; a grow knob. It tracks the motions of the mouse, and grows/draws the
- ; control appropriately.
- ;
- GrowFrame ANOP
- PushWord #2 ; set us to XOR mode. This is for the
- _SetPenMode ; rubber-banding effect of growing.
-
- jsr SetMyPen ; set my pen's width
-
- PushLong #GreyPattern ; grow with a grey pattern
- _SetPenPat
-
- ldy #oCtlMaxX ; get local copies of the maximum
- ldx #6 ; and minimum dimensions.
- loop0010 lda [<CtlPtr],y
- sta MinY,x
- dey
- dey
- dex
- dex
- bpl loop0010
-
- ; validate the min and max values. the min values must be at least $10.
- ; if not, they are set there. the max values must be at least as large
- ; as the min values. if not, they are set to $FFFF
-
- lda #$10
- cmp MinX
- blt ckMinY
- sta MinX
-
- ckMinY cmp MinY
- blt ckMaxX
- sta MinY
-
- ckMaxX lda MaxX
- cmp MinX
- bge ckMaxY
- ChgX lda #$FFFF
- sta MaxX
-
- ckMaxY lda MaxY
- cmp MinY
- bge doneCk
- ChgY lda #$FFFF
- sta MaxY
- doneCk ANOP
-
- ;
- ; We grow the control with the following algorithm. First, setup by:
- ;
- ; 1. saving the current mouse postion in 'NewMouse',
- ; 2. aligning 'NewMouse' to the grid, and
- ; 3. making a working copy of the control's rectangle in 'drag_rect'.
- ;
- ; We then enter the main loop:
- ;
- ; 4. Draw a copy of the rubber-banding rectangle.
- ; 5. Check the mouse button. If it is up, goto #12
- ; 6. Put the position of the mouse into 'NewerMouse'. Align it to grid.
- ; 7. Check it against 'NewMouse'. If it hasn't changed, goto #5.
- ; 8. Erase the old rubber-Band.
- ; 9. Calculate the new rectangle and put it into 'drag_rect'
- ; 10. Move 'NewerMouse' into 'NewMouse'
- ; 11. Goto #4
- ;
- ; The growing is all done. Clean up and leave.
- ;
- ; 12. Erase the rubber band.
- ; 13. Erase the control.
- ; 14. Invalidate the area under the control
- ; 15. Make drag_rect the new boundary of the control
- ; 16. Say goodnite, Gracie.
- ;
-
- lda OldMouse
- sta NewMouse
- lda OldMouse+2
- sta NewMouse+2
-
- ldx #^NewMouse ; make sure we are on the grid!!!
- lda #NewMouse
- jsr Snap2Grid
-
- DrawLoop ANOP
- PushLong #drag_rect ; draw the rubber-band
- _FrameRect
-
- WaitLoop ANOP
- pha ; has the mouse been lifted up?
- PushWord #mUpMask ; ask for any such events
- PushLong #TrackEvent
- _GetNextEvent
- pla
-
- lda TrackEvent+owhat
- cmp #mouseUpEvt
- beq done ; mouse up occured - so leave.
-
- lda TrackEvent+owhere ; mouse still down. copy it to
- sta NewerMouse ; NewerMouse
- lda TrackEvent+owhere+2
- sta NewerMouse+2
-
- PushLong #NewerMouse ; convert it to window coordinates.
- _GlobalToLocal
-
- ldx #^NewerMouse ; make sure the new position is on
- lda #NewerMouse ; the grid.
- jsr Snap2Grid
-
- lda NewerMouse ; See if the mouse position moved. We
- cmp NewMouse ; only redraw the rubber-band if it did.
- bne ReDraw ; It did - redraw the rubber-band
- lda NewerMouse+2
- cmp NewMouse+2
- beq WaitLoop ; No movement - check button state
-
- ReDraw ANOP
- PushLong #drag_rect ; erase the old rubber band
- _FrameRect
-
- lda NewerMouse ; copy NewerMouse for next loop
- sta NewMouse
- sec ; and update deltaXY for AdjFrameRect
- sbc OldMouse
- sta deltaY
-
- lda NewerMouse+2
- sta NewMouse+2
- sec
- sbc OldMouse+2
- sta deltaX
-
- jsr AdjFrameRect ; adjust for drawing the new rect
-
- brl DrawLoop ; redraw the rubber-band
-
- done ANOP
- PushLong #drag_rect ; erase the rubber band
- _FrameRect
-
- PushLong #myCtlRect ; erase the control
- _EraseRect
-
- PushLong #myCtlRect ; invalidate the stuff under it
- _InvalRect
-
- brl Exit
- ;
- ; This part of the program is called when we have clicked on either the
- ; frame or the interior. It calls dragrect to move an outline of the
- ; control around.
- ;
-
- DragFrame ANOP
-
- ; Get the portRect of the window that owns this control. This rectangle
- ; will be used to control the limits of dragging.
-
- ldy #octlOwner ; get the pointer to the control's
- lda [<CtlPtr],y ; owning window into 'work'
- sta <work
- iny
- iny
- lda [<CtlPtr],y
- sta <work+2
-
- ldy #oportRect+6 ; copy the PortRect of the window
- ldx #6 ; out of its GrafPort into limitRect.
- loop400 lda [<work],y
- sta limitRect,x
- dey
- dey
- dex
- dex
- bpl loop400
-
- ;
- ; Use dragRect to drag an outline of the control around the
- ; screen for me.
- ;
- pha ; space for result
- pha
- PushLong #DragDraw ; no action proc
- PushLong #GreyPattern ; drag pattern
- PushLong OldMouse ; starting location of mouse
- PushLong #drag_rect ; outline to drag
- PushLong #limitRect ; limitRect
- PushLong #limitRect ; slopRect
- PushWord #%00101000 ; custom drag flag, ReturnRect flag
- _DragRect
-
- pla ; pull off and discard the deltas
- pla
-
- PushLong #myCtlRect ; erase the control in its old pos'n
- _EraseRect
-
- PushLong #myCtlRect ; invalidate the stuff under it
- _InvalRect
-
- ldx #^drag_rect ; align the new rectangle to the grid.
- lda #drag_rect
- jsr Snap2Grid
-
- Exit ANOP
- ldy #6 ; copy over the new control frame
- loop200 lda drag_rect,y
- sta myCtlRect,y
- dey
- dey
- bpl loop200
-
- PushLong #myCtlRect ; Invalidate the new area under the
- _InvalRect ; control so it will be redrawn.
-
- PushLong #oldPenState
- _SetPenState ; clean up QuickDraw after ourselves.
-
- jsr SetCtlRect ; copy new rect into control record
-
- lda #-1 ; Say that we handled it
- tax
-
- rts
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- ; Called by DragRect to draw the rectangle of the control. I draw the outline
- ; myself so that I can align it to my own grid. The normal aligning of the
- ; rectangle to the grid only aligns to powers of 2. I align to anything.
- ;
- ; When this routine is called, the stack looks like this:
- ;
- ; PUSH:WORD - delta X
- ; PUSH:WORD - delta Y
- ; PUSH:BYTE[3] - return address
- ;
- ; However, since I set the ReturnRect flag, I can ignore the deltas passed to
- ; me, and use drag_rect directly. I make a copy of it, make sure that it is
- ; aligned to the grid, draw it, remove the parameters, and return to the
- ; control manager.
- ;
-
- DragDraw ANOP
-
- RTLAddr equ 1
- DY equ RTLAddr+3
- DX equ DY+2
-
- ldx #6 ; make a copy of the rectangle that
- loop500 lda drag_rect,x ; _DragRect is passing to us. We are
- sta draw_rect,x ; going to modify it so that it is
- dex ; aligned to the grid.
- dex
- bpl loop500
-
- ldx #^draw_rect ; align the new rectangle to the grid.
- lda #draw_rect
- jsr Snap2Grid
-
- DrawOutline ANOP
- PushLong #draw_rect
- _FrameRect
-
- ExitDragDraw ANOP
- lda 1,s ; move the RTL address back up
- sta 5,s
- lda 2,s
- sta 6,s
-
- pla ; remove the parameters (DX, DY)
- pla
-
- rtl ; back to dragRect!!
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- ; Called by the routine that grows the control with a rubber-band
- ; sort of thing. It uses the part code we hit as an index into
- ; a table. This table contains a list of offsets into the
- ; 4 words of drag_rect. It reads in a pair of these offsets and
- ; uses them to modify the appropriate X/Y coordinates with
- ; deltaY and deltaX. DeltaY and deltaX are set up by the
- ; rubber-banding routine.
-
- AdjFrameRect ANOP
- ldx #6
- loop380 lda drag_rect,x
- sta new_rect,x
- dex
- dex
- bpl loop380
-
- lda dragPart ; get the part code we are dragging
- sec
- sbc #ULPart
- asl a ; turn it into an index.
- asl a
- tax
- lda PtToAdj,x ; get Y coordinate to adjust
- tay
- lda PtToAdj+2,x ; get X coordinate to adjust
- tax
-
- ; if the entry that was fetched from the table was -1, then that means
- ; that we are making no adjustments in that direction. For instance, it
- ; we are dragging on the top edge knob, we want to adjust just the top
- ; side of the rectangle, but want to leave either of the sides alone.
-
- cpy #-1 ; modify the vertical coordinate
- beq NoChg1 ; of choice if necessary.
- clc
- lda deltaY
- adc myCtlRect,y
- sta new_rect,y
-
- NoChg1 cpx #-1 ; modify the horizontal coordinate
- beq NoChg2 ; of choice if necessary.
- clc
- lda deltaX
- adc myCtlRect,x
- sta new_rect,x
-
- NoChg2 ANOP
- ldx #^new_rect ; align the rectangle to the grid.
- lda #new_rect
- jsr Snap2Grid
-
- ; now that we have a new rectangle, we have to make sure that it is within
- ; the maximum and minimum sizes allowed.
-
- sec ; make sure the new Y size is OK
- lda new_rect+4
- sbc new_rect
- bcc NoCopy1
- cmp MinY
- blt NoCopy1 ; it's not, so leave old coords there
- inc a
- cmp MaxY
- bge NoCopy1 ; it's not, so leave old coords there
-
- lda new_rect ; it is, so update it.
- sta drag_rect
- lda new_rect+4
- sta drag_rect+4
-
- NoCopy1 ANOP
- sec ; make sure the new X size is OK
- lda new_rect+6
- sbc new_rect+2
- bcc NoCopy2
- cmp MinX
- blt NoCopy2 ; it's not, so leave old coords there
- inc a
- cmp MaxX
- bge NoCopy2 ; it's not, so leave old coords there
-
- lda new_rect+2 ; it is, so update it
- sta drag_rect+2
- lda new_rect+6
- sta drag_rect+6
- NoCopy2 ANOP
- rts
-
-
- PtToAdj dc i2'0,2,0,-1,0,6,-1,6,4,6,4,-1,4,2,-1,2'
-
- TrackEvent ds $10
-
- OldMouse ds 4
- NewMouse ds 8
- NewerMouse ds 8
- drag_rect ds 8
- draw_rect ds 8
- new_rect ds 8
- limitRect ds 8
- MinY ds 2
- MinX ds 2
- MaxY ds 2
- MaxX ds 2
-
- end
-
- EJECT
- *******************************************************************************
- *
- myNewValue start
- *
- * Description: Called when the value of the control is to be changed.
- * The area under the control is invalidated so that it will
- * be redrawn.
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs:
- * Import Snap2Grid
- * Import myDrawCtl
- * Import SetCtlRect
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- PushLong #myCtlRect ; erase old control
- _EraseRect
-
- PushLong #myCtlRect ; invalidate area erased
- _InvalRect
-
- ldx #^myCtlRect ; make sure control is on the grid
- lda #myCtlRect
- jsr Snap2Grid
-
- jsr SetCtlRect
-
- lda #0 ; return no value
- tax
-
- rts
- end
-
- EJECT
- *******************************************************************************
- *
- mySetParams start
- *
- * Description: Set new parameters command. Don't set if either of them
- * are negative.
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- lda theParam ; these have gotta go on in reverse
- sta <work+2
- lda theParam+2
- sta <work
-
- ora <work+2 ; is this a NULL pointer?
- bne CopyIt ; no - so use it
-
- lda #^StdCtlData ; yes - so set pointer to default data
- sta <work+2
- lda #StdCtlData
- sta <work
-
- CopyIt ANOP
- ldy #oCtlSize-2 ; copy the data into control record.
- ldx #oCtlSize-oCtlMinY-2
- loop phy
- txy
- lda [<work],y
- ply
- sta [<CtlPtr],y
- dey
- dey
- dex
- dex
- bpl loop
-
- lda #0 ; return no value
- tax
-
- rts
- end
-
- EJECT
- *******************************************************************************
- *
- myRecSize start
- *
- * Description: Return record size command.
- *
- *
- * Inputs: NONE
- *
- * Outputs: A = Size of the control record to allocate.
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- lda #oCtlSize ; low word of record size
- ldx #0 ; high word
-
- rts
- end
-
- EJECT
- *******************************************************************************
- *
- Null start
- *
- * Description: Null routine. Does nothing. Returns no error.
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
-
- lda #0
- tax
-
- rts
- end
-
- EJECT
- *******************************************************************************
- *
- InitCtlData start
- *
- * Description: Initialize some data that will needs to be handy: Get a
- * pointer to the control record (we are supplied only with
- * a handle), make a local copy of the control rectangle, set
- * up a pointer to a color table, and move CtlParam from a
- * Direct Page location into an absolute location.
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- ;
- ; Check to see if the Control Manager is sending us a 'RecSize' call. If it
- ; is, then we cannot rely on the validity of the Control handle, as it has not
- ; yet been allocated and is essentially garbage. Since we do not know what it
- ; points to, we don't want to read from it, as it may actually accidentally
- ; point to something dangerous, like the IWM I/O locations!!! So if we detect
- ; a RecSize code, skip over this routine.
- ;
- lda <CtlCode ; is this a RecSize call?
- cmp #recSize
- beq done ; yes - skip this whole routine
-
- ;
- ; Copy the value in CtlParam into a local location -- off of the direct page.
- ; We do this for convenience. We may need to pass a pointer to CtlParam to
- ; a toolbox routine, but you can't do that for a direct page location. The
- ; number assiciated with a direct page location is really an offset off of the
- ; base specified by the Direct Page register; it is NOT an absolute memory
- ; location. So that we can conveniently use 'PushLong #location' if we need
- ; to, I copy CtlParam to a non-direct page location.
- ;
- lda <CtlParam
- sta theParam
- lda <CtlParam+2
- sta theParam+2
-
- ldy #2 ; get a handy pointer to the CtlRec
- lda [<theCtlHandle],y
- sta <CtlPtr+2
- lda [<theCtlHandle]
- sta <CtlPtr
-
- ldy #octlRect+6 ; copy the control rect over to the
- ldx #6 ; local variable.
- loop lda [<CtlPtr],y
- sta myCtlRect,x
- dey
- dey
- dex
- dex
- bpl loop
-
- ;
- ; The following values are used by Snap2Grid. However, Snap2Grid can be
- ; called with an invalid Direct Page, so we copy them out the control
- ; record (which is pointed to by a pointer in our Direct Page) and into
- ; some absolute locations that we can get to at all times.
- ;
- ldy #oCtlGridX ; get the X and Y spacings out of the
- lda [<CtlPtr],y ; control record and into some local
- sta myCtlGridX ; storage for easy handling.
-
- ldy #oCtlGridY
- lda [<CtlPtr],y
- sta myCtlGridY
-
- ; Check the color table pointer. If it is non-zero, install it as the
- ; pointer to the color table we'll be using. If not, then install a
- ; pointer to a default color table.
-
- ldy #octlColor ; Get the pointer to the color
- lda [<CtlPtr],y ; table in the control record.
- sta ColorPtr ; Save it to a local pointer.
- iny
- iny
- lda [<CtlPtr],y
- sta ColorPtr+2
- ora ColorPtr ; is it a NULL pointer?
- bne done ; no, so use it.
-
- lda #StdColorTable ; yes, install my own color table.
- sta ColorPtr
- lda #^StdColorTable
- sta ColorPtr+2
-
- done ANOP
- rts
-
- end
-
- EJECT
- *******************************************************************************
- *
- SetCtlRect start
- *
- * Description: This routine is called when the control's bounding
- * rectangle has been changed and needs to be written back
- * out to the control record.
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- ldy #octlRect+6 ; get an offset into the control rec.
- ldx #6 ; index to my local record.
- loop ANOP
- lda myCtlRect,x
- sta [<CtlPtr],y
- dey
- dey
- dex
- dex
- bpl loop
-
- rts
-
- end
-
- EJECT
- *******************************************************************************
- *
- SetMyPen start
- *
- * Description: We want our control to look good in both 320 and 640 mode.
- * Because vertical lines are thinner in 640 than 320, its a
- * good idea to draw them doubly thick just so they can be
- * seen. This routine will determine what mode we are in and
- * adjust the pen accordingly.
- *
- *
- * Inputs: NONE
- *
- * Outputs: NONE
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- pha ; we base pen width on the MasterSCB
- _GetMasterSCB
- pla
- and #$0080 ; check the mode bit
- beq pen320 ; we are in 320 mode - go push a 1
-
- PushWord #2 ; in 640 mode - push on a 2 width
- bra setpn
-
- pen320 PushWord #1 ; in 320 mode - push on a 1 width
-
- setpn ANOP ; width is 1 or 2
- PushWord #1 ; Height is always 1
- _SetPenSize
-
- rts
- end
-
- EJECT
- *******************************************************************************
- *
- CalcCorners start
- *
- * Description: This routine calculates the rectangles for all of the
- * little knobs that are used to grow the control. They are
- * stored locally - not with the control record - and so need
- * to be calculated every time we need to check for hits or
- * to draw the control.
- *
- *
- * Inputs: NONE
- *
- * Outputs: knobXXX, FrameHeight, FrameWidth variables are initialized.
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- top equ 0 ; alias these to something a little
- left equ 2 ; more descriptive.
- bottom equ 4
- right equ 6
-
- ; Get the size of the knobs. The height and width are stored in the CtlValue
- ; field in a packed format. This unpacks them and stores them locally for
- ; ease of access.
-
- ldy #octlValue
- lda [<CtlPtr],y
- and #$00FF
- sta FrameHeight
- lda [<CtlPtr],y
- xba
- and #$00FF
- sta FrameWidth
-
- ;
- ; We "assembly line" the initialization of the knob rectangles. Instead
- ; of calculating just one knob at a time, we do a few of them all at the
- ; same time. Here we initialize the tops and bottoms of the 3 top knobs.
-
- lda myCtlRect+top
- sta knobUL+top
- sta knobTop+top
- sta knobUR+top
- clc
- adc FrameHeight
- sta knobUL+bottom
- sta knobTop+bottom
- sta knobUR+bottom
-
- ;
- ; Initialize the lefts and rights of the three left knobs.
- ;
- lda myCtlRect+left
- sta knobUL+left
- sta knobLeft+left
- sta knobLL+left
- clc
- adc FrameWidth
- sta knobUL+right
- sta knobLeft+right
- sta knobLL+right
-
- ;
- ; Initialize the tops and bottoms of the three bottom knobs.
- ;
- lda myCtlRect+bottom
- sta knobLL+bottom
- sta knobBottom+bottom
- sta knobLR+bottom
- sec
- sbc FrameHeight
- sta knobLL+top
- sta knobBottom+top
- sta knobLR+top
-
- ;
- ; Initialize the lefts and rights of the three right knobs.
- ;
- lda myCtlRect+right
- sta knobUR+right
- sta knobRight+right
- sta knobLR+right
- sec
- sbc FrameWidth
- sta knobUR+left
- sta knobRight+left
- sta knobLR+left
-
- ;
- ; At this point, the 4 corner knobs have been completely initialized.
- ; If we are going to be using the edge knobs, then we'll have to do
- ; some extra math. However, if we aren't, then we'll skip over the
- ; math.
-
- ldy #octlFlag
- lda [<CtlPtr],y
- and #knobEdgeMask
- beq done
-
- ; Do extra setup for edge knobs
- ;
- ; First, get top and bottom coordinates for the side edges:
- ;
- ; top = (myCtlRect.top + myCtlRect.bottom - FrameHeight)/2
- ; bot = (myCtlRect.top + myCtlRect.bottom + FrameHeight)/2
-
- clc
- lda myCtlRect+top
- adc myCtlRect+bottom
- pha
- adc FrameHeight
- lsr a
- sta knobLeft+bottom
- sta knobRight+bottom
- pla
- sec
- sbc FrameHeight
- lsr a
- sta knobLeft+top
- sta knobRight+top
-
- ;
- ; Now perform similar calculations for the left and right sides
- ; of the top and bottom edge knobs.
- ;
- clc
- lda myCtlRect+left
- adc myCtlRect+right
- pha
- adc FrameWidth
- lsr a
- sta knobTop+right
- sta knobBottom+right
- pla
- sec
- sbc FrameWidth
- lsr a
- sta knobTop+left
- sta knobBottom+left
-
- done ANOP
- rts
- end
-
- EJECT
- *******************************************************************************
- *
- Snap2Grid start
- *
- * Description: This control defproc lets the application optionally create
- * an invisible grid based on local coordinates. When this is
- * done, the 4 corners of the control are always aligned to
- * the coordinates of this grid. This occurs when we drag or
- * resize the control, or call MoveControl. Snap2Grip is the
- * routine that ensures we are on the grid.
- *
- *
- * Inputs: A = low word of pointer to rectangle to fix
- * X = high word
- *
- * Outputs: rectangle is modified in place.
- *
- * External Refs: NONE
- *
- * Entry Points: NONE
- *
- *******************************************************************************
- using CtlData
-
- oldD equ 1
- oldB equ oldD+2
- rectPtr equ oldB+1
-
- ;
- ; We are going to use a local direct page here. This is because Snap2Grid is
- ; called by my routine that draws the control's recangle as it is being
- ; dragged. When that happens, we are not using our normal direct page, and
- ; hence can't use any of the values or work locations there. So we set up
- ; another one with it's own workspace.
- ;
- phx ; save the pointer to the rectangle
- pha
-
- phb ; save the caller's data bank register
- phd ; save the caller'd direct page reg.
-
- phk ; switch data bank to program bank
- plb
-
- tsc ; switch direct page to stack pointer
- tcd
-
-
- ;
- ; WhchGridYX is used to help generalize this routine. We support different
- ; spacings in the X and Y directions of the grid. As we loop through all 4
- ; coordinates of the rectangle, we want to make sure that we are using the
- ; correct spacing. 'whichGridYX' holds flags that tell us when to use X and
- ; when to use Y spacing (0 = use Y spacing; 1 = use X spacing).
- ;
- lda #%0101 ; Set up some indices into GridYX
- sta whichGridYX
-
- ;
- ; Fix the coordinates by using the following method:
- ;
- ; 1. Get the difference between the coordinate we are examining and
- ; the next lowest grid location:
- ;
- ; z = coordinate mod GridSize
- ;
- ; 2. Z tells how far away from the next lowest grid line
- ; the coordinate we are looking at is, so subtracting that
- ; value will put the coordinate on the grid.
- ;
- ; coordinate := coordinate - z
- ;
- ; 3. However, this is simply truncating, and I don't like the
- ; way that feels when resizing the control. So lets add an
- ; instruction so that it ROUNDS instead.
- ;
- ; if z > GridSize/2 then
- ; coordinate := coordinate + GridSize
- ;
-
- ldy #6 ; init our loop index
- Loop ANOP
- sty YSave
-
- lda whichGridYX ; do we now use X or Y grid spacing?
- and #%0001
- beq UseY
- lda myCtlGridX
- bra UseIt
- UseY ANOP
- lda myCtlGridY
-
- ; we now have the gridsize in the Acc
- UseIt ANOP
- cmp #2 ; Is it 0 or 1? If so, then skip over
- blt ShortCircuit ; dividing routine.
- sta GridSize ; save this for the divide later.
-
- pha ; push space on stack for the result
- pha ; of the divide we are going to do.
-
- lda [<rectPtr],y ; push on the coordinate we are
- pha ; adjusting as the Dividend
- PushWord GridSize ; push this on as the divisor
- _UDivide ; unsigned divide
- pla ; quotient - we don't want it.
- PullWord Remainder ; remainder is 'z' - Keep it!
-
- ldy YSave ; get my coordinate index back.
- lda [<rectPtr],y ; get the coordinate to change
- sec
- sbc Remainder ; change it
- sta [<rectPtr],y ; save it back out
-
- lda GridSize ; Make a GridSize/2
- lsr a
- cmp Remainder ; is remainder < GridSize/2?
- bge ShortCircuit ; yes - so we're done
- lda [<rectPtr],y ; no - so bump the coordinate
- clc
- adc GridSize
- sta [<rectPtr],y
-
- ShortCircuit lsr whichGridYX ; move the next index into place
- dey ; bump down to the next coordinate
- dey ; of the rectangle.
- bpl Loop
-
- Exit ANOP
- pld ; restore caller's Direct Page reg.
- plb ; restore data bank register
- pla ; remove rect pointer
- pla
- rts ; all done - go bye-bye
-
- whichGridYX ds 2
- YSave ds 2
- Remainder ds 2
- GridSize ds 2
-
- end
-
- EJECT
- *******************************************************************************
- *
- FindPart start
- *
- * Description: This routine is called to find out exactly which part of
- * the control we clicked in. It first checks to see if we
- * clicked in any of the grow knobs. If so, then it returns
- * an 'internal partcode' telling the calling routine which
- * knob was clicked in. If a knob wasn't clicked in, a check
- * is made to see if we clicked on the frame. If we are
- * allowed to click in the interior, a check is made to see
- * if we clicked there, too.
- *
- *
- * Inputs: NONE
- *
- * Outputs: A = internal partcode of part hit (1-10)
- *
- * External Refs:
- * Import CalcCorners
- *
- * Entry Points:
- * entry TestFrame ; called by myTestCtl
- *
- *******************************************************************************
- using CtlData
-
- jsr CalcCorners
-
- ;
- ; We first check to see if the mouse was clicked in any of the knobs. We do
- ; this by assuming a knob was clicked in, and then checking to see if that was
- ; true. If so, we leave here with the partcode we assumed. If not, we loop
- ; through and check all of the other knobs. If none of the knobs was clicked
- ; in, we see if the frame was clicked on.
-
- ldx #LeftPart ; get last knob's part code
- ldy #7*8 ; point to last knob's rect
-
- loop ANOP
- phx ; save partcode we're checking for...
- phy ; and the rect's pointer
-
- pha ; space for _PtInRect result
- PushLong #theParam ; push on the point to check
- lda #^knobUL ; create a pointer to the rect
- pha
- clc ; Bumping just the low byte is OK
- tya ; unless the GS suddenly lets
- adc #knobUL ; code segments cross bank
- pha ; boundaries
- _PtInRect
- pla ; get result of PtInRect
- ply ; retrieve rectangle index
- plx ; retrieve part code
- cmp #0 ; did we score a hit?
- bne InKnob ; yes, return with the part code
- dex ; move down to next partcode
- sec ; move down to next rectangle
- tya
- sbc #8
- tay
- bpl loop ; keep going until rect index < 0
-
- bra TestFrame ; not in knobs - try frame
-
- ;
- ; We just scored a hit on one of the knobs, and X holds the knob number.
- ; However, the application may not have corner or edge knobs active. So
- ; if we clicked on an inactive knob, have to check for that and return
- ; 'inFrame' instead of a knob partcode.
- ;
- InKnob ANOP
- ldy #octlFlag ; are corner knobs active?
- lda [<CtlPtr],y
- and #knobCornerMask
- bne ckEdge ; yes - so pass this code on.
-
- txa ; Corners not allowed. Did we hit one?
- lsr a
- bcs RetFramePart ; yes, so return click on Frame instead
-
- ckEdge ANOP
- ldy #octlFlag ; are edge knobs active?
- lda [<CtlPtr],y
- and #knobEdgeMask
- bne done ; yes - so return this code
-
- txa ; Edges not allowed. Did we hit one?
- lsr a
- bcs TestFrame ; no, so pass this code on.
- RetFramePart ANOP
- ldx #FramePart ; yes, so return click on Frame instead
- done ANOP
- txa ; put the part code in the Acc
- rts
-
- TestFrame entry
-
- ; First test to see if it is within the Control's rectangle. It should
- ; be, but let's check anyway...
-
- pha
- PushLong #theParam
- PushLong #myCtlRect
- _PtInRect
- pla
- beq NotInFrame ; no in the frame. Signal noPart
-
- ; Now see if we differentiate between the frame and the interior
-
- ldy #octlFlag
- lda [<CtlPtr],y
- and #dragIntMask
- bne RetFramePart ; nope - everything drags
-
- ; Yes we do. Now see if we hit the frame fair and square. Inset the
- ; control's bounding rectangle by the size of the knobs that are on
- ; it to create an inner rectangle. If we fall between those two
- ; rectangles, then I say that you have landed on the frame. If we
- ; got this far, then we know that we are within the outer rectangle.
- ; Now see if we are outside of the inner rectangle.
-
- ldx #6 ; make a copy of the control rect
- CopyLoop lda myCtlRect,x ; so that we can reduce it.
- sta innerRect,x
- dex
- dex
- bpl CopyLoop
-
- PushLong #innerRect ; push on pointer to the rect to inset
- PushWord FrameWidth ; push on the amounts to inset it by
- PushWord FrameHeight ; (these vals inited by CalcCorners)
- _InsetRect
-
- pha ; see if we are outside of the inner
- PushLong #theParam ; rectangle
- PushLong #innerRect
- _PtInRect
-
- pla ; check the result
- beq RetFramePart ; we were between rects!
-
- NotInFrame lda #noPart ; Not *exactly* on the frame.
- rts
-
- innerRect ds 8
-
- end
-